home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung 2 / Power-Programmierung CD 2 (Tewi)(1994).iso / gnu / gnulib / rcs4 / source / rcslex.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-03-08  |  24.7 KB  |  800 lines

  1. /*
  2.  *                     RCS file input
  3.  */
  4. #ifndef lint
  5. static char rcsid[]= "$Id: rcslex.c 5.2 90/07/15 11:34:18 ROOT_DOS Release $ Purdue CS";
  6. #endif
  7. /*********************************************************************************
  8.  *                     Lexical Analysis.
  9.  *                     Character mapping table,
  10.  *                     hashtable, Lexinit, nextlex, getlex, getkey,
  11.  *                     getid, getnum, readstring, printstring, savestring,
  12.  *                     checkid, serror, fatserror, error, faterror, warn, diagnose
  13.  *                     fflsbuf, puts, fprintf
  14.  *                     Testprogram: define LEXDB
  15.  *********************************************************************************
  16.  */
  17.  
  18. /* Copyright (C) 1982, 1988, 1989 Walter Tichy
  19.    Distributed under license by the Free Software Foundation, Inc.
  20.  
  21. This file is part of RCS.
  22.  
  23. RCS is free software; you can redistribute it and/or modify
  24. it under the terms of the GNU General Public License as published by
  25. the Free Software Foundation; either version 1, or (at your option)
  26. any later version.
  27.  
  28. RCS is distributed in the hope that it will be useful,
  29. but WITHOUT ANY WARRANTY; without even the implied warranty of
  30. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  31. GNU General Public License for more details.
  32.  
  33. You should have received a copy of the GNU General Public License
  34. along with RCS; see the file COPYING.  If not, write to
  35. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  36.  
  37. Report problems and direct all questions to:
  38.  
  39.     rcs-bugs@cs.purdue.edu
  40.  
  41. */
  42.  
  43.  
  44.  
  45. /* $Log:    rcslex.c $
  46.  * Revision 5.2  90/07/15  11:34:18  ROOT_DOS
  47.  * checked in with -k by ROOT_DOS at 91.02.07.11.45.33.
  48.  * 
  49.  * Revision 5.2  90/07/15  11:34:18  ROOT_DOS
  50.  * DOS version of RCS 4.0 checked in for MODS
  51.  * by lfk@athena.mit.edu
  52.  * Also update to MSC 6.0
  53.  * 
  54.  * Revision 4.6  89/05/01  15:13:07  narten
  55.  * changed copyright header to reflect current distribution rules
  56.  * 
  57.  * Revision 4.5  88/11/08  12:00:54  narten
  58.  * changes from  eggert@sm.unisys.com (Paul Eggert)
  59.  * 
  60.  * Revision 4.5  88/08/28  15:01:12  eggert
  61.  * Don't loop when writing error messages to a full filesystem.
  62.  * Flush stderr/stdout when mixing output.
  63.  * Yield exit status compatible with diff(1).
  64.  * Shrink stdio code size; allow cc -R; remove lint.
  65.  * 
  66.  * Revision 4.4  87/12/18  11:44:47  narten
  67.  * fixed to use "varargs" in "fprintf"; this is required if it is to
  68.  * work on a SPARC machine such as a Sun-4
  69.  * 
  70.  * Revision 4.3  87/10/18  10:37:18  narten
  71.  * Updating version numbers. Changes relative to 1.1 actually relative
  72.  * to version 4.1
  73.  * 
  74.  * Revision 1.3  87/09/24  14:00:17  narten
  75.  * Sources now pass through lint (if you ignore printf/sprintf/fprintf 
  76.  * warnings)
  77.  * 
  78.  * Revision 1.2  87/03/27  14:22:33  jenkins
  79.  * Port to suns
  80.  * 
  81.  * Revision 1.1  84/01/23  14:50:33  kcs
  82.  * Initial revision
  83.  * 
  84.  * Revision 4.1  83/03/25  18:12:51  wft
  85.  * Only changed $Header to $Id.
  86.  * 
  87.  * Revision 3.3  82/12/10  16:22:37  wft
  88.  * Improved error messages, changed exit status on error to 1.
  89.  *
  90.  * Revision 3.2  82/11/28  21:27:10  wft
  91.  * Renamed ctab to map and included EOFILE; ctab is now a macro in rcsbase.h.
  92.  * Added fflsbuf(), fputs(), and fprintf(), which abort the RCS operations
  93.  * properly in case there is an IO-error (e.g., file system full).
  94.  *
  95.  * Revision 3.1  82/10/11  19:43:56  wft
  96.  * removed unused label out:;
  97.  * made sure all calls to getc() return into an integer, not a char.
  98.  */
  99.  
  100.  
  101. /*
  102. #define LEXDB
  103. /* version LEXDB is for testing the lexical analyzer. The testprogram
  104.  * reads a stream of lexemes, enters the revision numbers into the
  105.  * hashtable, and prints the recognized tokens. Keywords are recognized
  106.  * as identifiers.
  107.  */
  108.  
  109.  
  110.  
  111. #include "rcsbase.h"
  112. #include <varargs.h>
  113.  
  114.  
  115.  
  116. /* character mapping table */
  117. enum tokens map[] = {
  118.         EOFILE,         /* this will end up at ctab[-1] */
  119.         UNKN,   INSERT, UNKN,   UNKN,   UNKN,   UNKN,   UNKN,   UNKN,
  120.         UNKN,   SPACE,  NEWLN,  UNKN,   SPACE,  UNKN,   UNKN,   UNKN,
  121.         UNKN,   UNKN,   UNKN,   UNKN,   UNKN,   UNKN,   UNKN,   UNKN,
  122.         UNKN,   UNKN,   UNKN,   UNKN,   UNKN,   UNKN,   UNKN,   UNKN,
  123.         SPACE,  EXCLA,  DQUOTE, HASH,   DOLLAR, PERCNT, AMPER,  SQUOTE,
  124.         LPARN,  RPARN,  TIMES,  PLUS,   COMMA,  MINUS,  PERIOD, DIVIDE,
  125.         DIGIT,  DIGIT,  DIGIT,  DIGIT,  DIGIT,  DIGIT,  DIGIT,  DIGIT,
  126.         DIGIT,  DIGIT,  COLON,  SEMI,   LESS,   EQUAL,  GREAT,  QUEST,
  127.         AT,     LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
  128.         LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
  129.         LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
  130.         LETTER, LETTER, LETTER, LBRACK, BACKSL, RBRACK, UPARR,  UNDER,
  131.         ACCENT, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
  132.         LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
  133.         LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
  134.         LETTER, LETTER, LETTER, LBRACE, BAR,    RBRACE, TILDE,  UNKN
  135. };
  136.  
  137.  
  138.  
  139.  
  140. struct hshentry * nexthsh;  /*pointer to next hashtable-entry, set by lookup*/
  141.  
  142. enum tokens     nexttok;    /*next token, set by nextlex                    */
  143.  
  144. int             hshenter;   /*if true, next suitable lexeme will be entered */
  145.                             /*into the symbol table. Handle with care.      */
  146. int             nextc;      /*next input character, initialized by Lexinit  */
  147.  
  148. #ifdef MSDOS
  149. int             eoftok;        /*end-of-file indicator, set to >0 on end of file*/
  150. #else
  151. int             eof;        /*end-of-file indicator, set to >0 on end of file*/
  152. #endif /* MSDOS */
  153. int             line;       /*current line-number of input                  */
  154. int             nerror;     /*counter for errors                            */
  155. int             nwarn;      /*counter for warnings                          */
  156. char *          cmdid;      /*command identification for error messages     */
  157. int             quietflag;  /*indicates quiet mode                          */
  158. FILE *          finptr;     /*input file descriptor                         */
  159.  
  160. FILE *          frewrite;   /*file descriptor for echoing input             */
  161.  
  162. int             rewriteflag;/*indicates whether to echo to frewrite         */
  163.  
  164. char            StringTab[strtsize]; /* string table and heap               */
  165.  
  166. char *          NextString;         /*pointer to next identifier in StringTab*/
  167. char *          Topchar;            /*pointer to next free byte in StringTab*/
  168.                                     /*set by nextlex, lookup                */
  169. struct hshentry hshtab[hshsize];    /*hashtable                             */
  170.  
  171.  
  172.  
  173.  
  174.  
  175. lookup() {
  176.  
  177. /* Function: Looks up the character string pointed to by NextString in the
  178.  * hashtable. If the string is not present, a new entry for it is created.
  179.  * If the string is present, TopChar is moved back to save the space for
  180.  * the string, and NextString is set to point to the original string.
  181.  * In any case, the address of the corresponding hashtable entry is placed
  182.  * into nexthsh.
  183.  * Algorithm: Quadratic hash, covering all entries.
  184.  * Assumptions: NextString points at the first character of the string.
  185.  * Topchar points at the first empty byte after the string.
  186.  */
  187.  
  188.         register int     ihash;      /* index into hashtable */
  189.         register char    * sp, * np;
  190.         int              c, delta, final, FirstScan; /*loop control*/
  191.  
  192.         /* calculate hash code */
  193.         sp = NextString;
  194.         ihash = 0;
  195.         while (*sp) ihash += *sp++;
  196.  
  197.         /* set up first search loop (c=0,step=1,until (hshsiz-1)/2 */
  198.         c=0;delta=1;final=(hshsize-1)/2;
  199.         FirstScan=true;   /*first loop */
  200.  
  201.         for (;;) {
  202.                 ihash = (ihash+c)%hshsize;   /*next index*/
  203.  
  204.                 if (hshtab[ihash].num == nil) {
  205.                         /*empty slot found*/
  206.                         hshtab[ihash].num = NextString;
  207.                         nexthsh= &hshtab[ihash];/*save hashtable address*/
  208. #                       ifdef LEXDB
  209.                         VOID printf("\nEntered: %s at %d ",nexthsh->num, ihash);
  210. #                       endif
  211.                         return;
  212.                 }
  213.                 /* compare strings */
  214.                 sp=NextString;np=hshtab[ihash].num;
  215.                 while (*sp == *np++) {
  216.                         if (*sp == 0) {
  217.                                 /* match found */
  218.                                 nexthsh= &hshtab[ihash];
  219.                                 Topchar = NextString;
  220.                                 NextString = nexthsh->num;
  221.                                 return;
  222.                         } else sp++;
  223.                 }
  224.  
  225.                 /* neither empty slot nor string found */
  226.                 /* calculate next index and repeat */
  227.                 if (c != final)
  228.                         c += delta;
  229.                 else {
  230.                         if (FirstScan) {
  231.                                 /*set up second sweep*/
  232.                                 delta = -1; final = 1; FirstScan= false;
  233.                         } else {
  234.                                 fatserror("Hashtable overflow");
  235.                         }
  236.                 }
  237.         }
  238. };
  239.  
  240.  
  241.  
  242.  
  243.  
  244.  
  245. Lexinit()
  246. /* Function: Initialization of lexical analyzer:
  247.  * initializes the hastable,
  248.  * initializes nextc, nexttok if finptr != NULL
  249.  */
  250. {       register int            c;
  251.  
  252.         for (c=hshsize-1; c>=0; c--) {
  253.                 hshtab[c].num = nil;
  254.         }
  255.  
  256. #ifdef MSDOS
  257.         hshenter=true; eoftok=0; line=1; nerror=0; nwarn=0;
  258. #else
  259.         hshenter=true; eof=0; line=1; nerror=0; nwarn=0;
  260. #endif /* MSDOS */
  261.         NextString=nil; Topchar = &StringTab[0];
  262.         if (finptr) {
  263.                 nextc = GETC(finptr,frewrite,rewriteflag); /*initial character*/
  264.                 nextlex();            /*initial token*/
  265.         } else {
  266.                 nextc = '\0';
  267.                 nexttok=EOFILE;
  268.         }
  269. }
  270.  
  271.  
  272.  
  273.  
  274.  
  275.  
  276.  
  277. nextlex()
  278.  
  279. /* Function: Reads the next token and sets nexttok to the next token code.
  280.  * Only if the hshenter==true, a revision number is entered into the
  281.  * hashtable and a pointer to it is placed into nexthsh.
  282.  * This is useful for avoiding that dates are placed into the hashtable.
  283.  * For ID's and NUM's, NextString is set to the character string in the
  284.  * string table. Assumption: nextc contains the next character.
  285.  */
  286. {       register c;
  287.     register FILE * fin, * frew;
  288.         register char * sp;
  289.         register enum tokens d;
  290.  
  291. #ifdef MSDOS
  292.         if (eoftok) {
  293. #else
  294.         if (eof) {
  295. #endif /* MSDOS */
  296.                 nexttok=EOFILE;
  297.                 return;
  298.         }
  299.     fin=finptr; frew=frewrite;
  300. loop:
  301.         switch(nexttok=ctab[nextc]) {
  302.  
  303.         case UNKN:
  304.         case IDCHAR:
  305.         case PERIOD:
  306.                 serror("unknown Character: %c",nextc);
  307.                 nextc=GETC(fin,frew,rewriteflag);
  308.                 goto loop;
  309.  
  310.         case NEWLN:
  311.                 line++;
  312. #               ifdef LEXDB
  313.                 VOID putchar('\n');
  314. #               endif
  315.                 /* Note: falls into next case */
  316.  
  317.         case SPACE:
  318.                 nextc=GETC(fin,frew,rewriteflag);
  319.                 goto loop;
  320.  
  321.         case EOFILE:
  322. #ifdef MSDOS
  323.                 eoftok++;
  324. #else
  325.                 eof++;
  326. #endif /* MSDOS */
  327.                 nexttok=EOFILE;
  328.                 return;
  329.  
  330.         case DIGIT:
  331.                 NextString = sp = Topchar;
  332.                 *sp++ = nextc;
  333.                 while ((d=ctab[c=GETC(fin,frew,rewriteflag)])==DIGIT ||
  334.                         d==PERIOD) {
  335.                         *sp++ = c;         /* 1.2. and 1.2 are different */
  336.                 }
  337.                 *sp++ = '\0';
  338.                 if (sp >= StringTab+strtsize) {
  339.                         /*may have written outside stringtable already*/
  340.                         fatserror("Stringtable overflow");
  341.                 }
  342.                 Topchar = sp;
  343.                 nextc = c;
  344.                 if (hshenter == true)
  345.                         lookup();      /* lookup updates NextString, Topchar*/
  346.                 nexttok = NUM;
  347.                 return;
  348.  
  349.  
  350.         case LETTER:
  351.                 NextString = sp = Topchar;
  352.                 *sp++ = nextc;
  353.                 while ((d=ctab[c=GETC(fin,frew,rewriteflag)])==LETTER ||
  354.                         d==DIGIT || d==IDCHAR) {
  355.                         *sp++ = c;
  356.                 }
  357.                 *sp++ = '\0';
  358.                 if (sp >= StringTab+strtsize) {
  359.                         /*may have written outside stringtable already*/
  360.                         fatserror("Stringtable overflow");
  361.                 }
  362.                 Topchar = sp;
  363.                 nextc = c;
  364.                 nexttok = ID;  /* may be ID or keyword */
  365.                 return;
  366.  
  367.         case SBEGIN: /* long string */
  368.                 nexttok = STRING;
  369.                 /* note: only the initial SBEGIN has been read*/
  370.                 /* read the string, and reset nextc afterwards*/
  371.                 return;
  372.  
  373.         default:
  374.                 nextc=GETC(fin,frew,rewriteflag);
  375.                 return;
  376.         }
  377. }
  378.  
  379.  
  380. int getlex(token)
  381. enum tokens token;
  382. /* Function: Checks if nexttok is the same as token. If so,
  383.  * advances the input by calling nextlex and returns true.
  384.  * otherwise returns false.
  385.  * Doesn't work for strings and keywords; loses the character string for ids.
  386.  */
  387. {
  388.         if (nexttok==token) {
  389.                 nextlex();
  390.                 return(true);
  391.         } else  return(false);
  392. }
  393.  
  394. int getkey (key)
  395. char * key;
  396. /* Function: If the current token is a keyword identical to key,
  397.  * getkey advances the input by calling nextlex and returns true;
  398.  * otherwise returns false.
  399.  */
  400. {
  401.         register char *s1,*s2;
  402.  
  403.         if (nexttok==ID) {
  404.                 s1=key; s2=NextString;
  405.                 while(*s1 == *s2++)
  406.                      if (*s1++ == '\0') {
  407.                          /* match found */
  408.                          Topchar = NextString; /*reset Topchar */
  409.                          nextlex();
  410.                          return(true);
  411.                      }
  412.         }
  413.         return(false);
  414. }
  415.  
  416.  
  417.  
  418. char * getid()
  419. /* Function: Checks if nexttok is an identifier. If so,
  420.  * advances the input by calling nextlex and returns a pointer
  421.  * to the identifier; otherwise returns nil.
  422.  * Treats keywords as identifiers.
  423.  */
  424. {
  425.         register char * name;
  426.         if (nexttok==ID) {
  427.                 name = NextString;
  428.                 nextlex();
  429.                 return name;
  430.         } else  return nil;
  431. }
  432.  
  433.  
  434. struct hshentry * getnum()
  435. /* Function: Checks if nexttok is a number. If so,
  436.  * advances the input by calling nextlex and returns a pointer
  437.  * to the hashtable entry. Otherwise returns nil.
  438.  * Doesn't work if hshenter is false.
  439.  */
  440. {
  441.         register struct hshentry * num;
  442.         if (nexttok==NUM) {
  443.                 num=nexthsh;
  444.                 nextlex();
  445.                 return num;
  446.         } else  return nil;
  447. }
  448.  
  449.  
  450. readstring()
  451. /* skip over characters until terminating single SDELIM        */
  452. /* if rewriteflag==true, copy every character read to frewrite.*/
  453. /* Does not advance nextlex at the end.                        */
  454. {       register c;
  455.     register FILE * fin,  * frew;
  456.     fin=finptr; frew=frewrite;
  457.         if (rewriteflag) {
  458.                 /* copy string verbatim to frewrite */
  459.                 while ((c=getc(fin)) != EOF) {
  460.             VOID putc(c,frew);
  461.                         if (c==SDELIM) {
  462.                                 if ((c=getc(fin)) == EOF || putc(c,frew) != SDELIM) {
  463.                                         /* end of string */
  464.                                         nextc=c;
  465.                                         return;
  466.                                 }
  467.                         }
  468.                 }
  469.         } else {
  470.                 /* skip string */
  471.                 while ((c=getc(fin)) != EOF) {
  472.                         if (c==SDELIM) {
  473.                                 if ((c=getc(fin)) != SDELIM) {
  474.                                         /* end of string */
  475.                                         nextc=c;
  476.                                         return;
  477.                                 }
  478.                         }
  479.                 }
  480.         }
  481.         nextc = c;
  482.         error("Unterminated string");
  483. }
  484.  
  485.  
  486. printstring()
  487. /* Function: copy a string to stdout, until terminated with a single SDELIM.
  488.  * Does not advance nextlex at the end.
  489.  */
  490. {
  491.         register c;
  492.     register FILE * fin;
  493.     fin=finptr;
  494.     while ((c=getc(fin)) != EOF) {
  495.                 if (c==SDELIM) {
  496.             if ((c=getc(fin)) != SDELIM) {
  497.                                 /* end of string */
  498.                                 nextc=c;
  499.                                 return;
  500.                         }
  501.                 }
  502.                 VOID putchar(c);
  503.         }
  504.         nextc = c;
  505.         error("Unterminated string");
  506. }
  507.  
  508.  
  509.  
  510. savestring(target,length)
  511. char * target; int length;
  512. /* copies a string terminated with SDELIM from file finptr to buffer target,
  513.  * but not more than length bytes. If the string is longer than length,
  514.  * the extra characters are skipped. The string may be empty, in which
  515.  * case a '\0' is placed into target.
  516.  * Double SDELIM is replaced with SDELIM.
  517.  * If rewriteflag==true, the string is also copied unchanged to frewrite.
  518.  * Returns the length of the saved string.
  519.  * Does not advance nextlex at the end.
  520.  */
  521. {
  522.         register c;
  523.     register FILE * fin, * frew;
  524.         register char * tp, * max;
  525.  
  526.     fin=finptr; frew=frewrite;
  527.         tp=target; max= target+length; /*max is one too large*/
  528.         while ((c=GETC(fin,frew,rewriteflag))!=EOF) {
  529.         *tp++ =c;
  530.                 if (c== SDELIM) {
  531.                         if ((c=GETC(fin,frew,rewriteflag))!=SDELIM) {
  532.                                 /* end of string */
  533.                                 *(tp-1)='\0';
  534.                                 nextc=c;
  535.                                 return;
  536.                         }
  537.                 }
  538.                 if (tp >= max) {
  539.                         /* overflow */
  540.                         error("string buffer overflow -- truncating string");
  541.                         target[length-1]='\0';
  542.                         /* skip rest of string */
  543.                         while ((c=GETC(fin,frew,rewriteflag))!=EOF) {
  544.                                 if ((c==SDELIM) && ((c=GETC(fin,frew,rewriteflag))!=SDELIM)) {
  545.                                         /* end of string */
  546.                                         nextc=c;
  547.                                         return;
  548.                                 }
  549.                         }
  550.                         nextc = c;
  551.                         error("Can't find %c to terminate string before end of file",SDELIM);
  552.                         return;
  553.                 }
  554.         }
  555.         nextc = c;
  556.         error("Can't find %c to terminate string before end of file",SDELIM);
  557. }
  558.  
  559.  
  560. char  *checkid(id, delim)
  561. char    *id, delim;
  562. /*   Function:  check whether the string starting at id is an   */
  563. /*              identifier and return a pointer to the last char*/
  564. /*              of the identifer. White space, delim and '\0'   */
  565. /*              are legal delimeters. Aborts the program if not */
  566. /*              a legal identifier. Useful for checking commands*/
  567. {
  568.         register enum  tokens  d;
  569.         register char    *temp;
  570.         register char    c,tc;
  571.  
  572.         temp = id;
  573.         if ( ctab[*id] == LETTER ) {
  574.             while( (d=ctab[c=(*++id)]) == LETTER || d==DIGIT || d==IDCHAR) ;
  575.             if ( c!=' ' && c!='\t' && c!='\n' && c!='\0' && c!=delim) {
  576.                 /* append \0 to end of id before error message */
  577.                 tc = c;
  578.                 while( (c=(*++id))!=' ' && c!='\t' && c!='\n' && c!='\0' && c!=delim) ;
  579.                 *id = '\0';
  580.                 faterror("Invalid character %c in identifier %s",tc,temp);
  581.                 return nil ;
  582.             } else
  583.                 return id;
  584.         } else {
  585.             /* append \0 to end of id before error message */
  586.             while( (c=(*++id))!=' ' && c!='\t' && c!='\n' && c!='\0' && c!=delim) ;
  587.             *id = '\0';
  588.             faterror("Identifier %s does not start with letter",temp);
  589.             return nil;
  590.         }
  591. }
  592.  
  593. writeerror()
  594. {
  595.     static looping;
  596.     if (looping)
  597.         exit(2);
  598.     looping = 1;
  599.     faterror("write error");
  600. }
  601.  
  602. nlflush(iop)
  603. register FILE * iop;
  604. {
  605.     if (putc('\n',iop)==EOF || fflush(iop)==EOF)
  606.                 writeerror();
  607. }
  608.  
  609.  
  610. /*VARARGS1*/
  611. serror(e,e1,e2,e3,e4,e5)
  612. char * e, * e1, * e2, * e3, * e4, * e5;
  613. /* non-fatal syntax error */
  614. {       nerror++;
  615.         VOID fprintf(stderr,"%s error, line %d: ", cmdid, line);
  616.         VOID fprintf(stderr,e, e1, e2, e3, e4, e5);
  617.         nlflush(stderr);
  618. }
  619.  
  620. /*VARARGS1*/
  621. error(e,e1,e2,e3,e4,e5)
  622. char * e, * e1, * e2, * e3, * e4, * e5;
  623. /* non-fatal error */
  624. {       nerror++;
  625.         VOID fprintf(stderr,"%s error: ",cmdid);
  626.         VOID fprintf(stderr,e, e1, e2, e3, e4, e5);
  627.         nlflush(stderr);
  628. }
  629.  
  630. /*VARARGS1*/
  631. fatserror(e,e1,e2,e3,e4,e5)
  632. char * e, * e1, * e2, * e3, * e4, * e5;
  633. /* fatal syntax error */
  634. {       nerror++;
  635.         VOID fprintf(stderr,"%s error, line %d: ", cmdid,line);
  636.         VOID fprintf(stderr,e, e1, e2, e3, e4, e5);
  637.         VOID fprintf(stderr,"\n%s aborted\n",cmdid);
  638.         VOID cleanup();
  639.         exit(2);
  640. }
  641.  
  642. /*VARARGS1*/
  643. faterror(e,e1,e2,e3,e4,e5)
  644. char * e, * e1, * e2, * e3, * e4, * e5;
  645. /* fatal error, terminates program after cleanup */
  646. {       nerror++;
  647.         VOID fprintf(stderr,"%s error: ",cmdid);
  648.         VOID fprintf(stderr,e, e1, e2, e3, e4, e5);
  649.         VOID fprintf(stderr,"\n%s aborted\n",cmdid);
  650.         VOID cleanup();
  651.         exit(2);
  652. }
  653.  
  654. /*VARARGS1*/
  655. warn(e,e1,e2,e3,e4,e5)
  656. char * e, * e1, * e2, * e3, * e4, * e5;
  657. /* prints a warning message */
  658. {       nwarn++;
  659.         VOID fprintf(stderr,"%s warning: ",cmdid);
  660.         VOID fprintf(stderr,e, e1, e2, e3, e4, e5);
  661.         nlflush(stderr);
  662. }
  663.  
  664.  
  665. /*VARARGS1*/
  666. diagnose(e,e1,e2,e3,e4,e5)
  667. char * e, * e1, * e2, * e3, * e4, * e5;
  668. /* prints a diagnostic message */
  669. {
  670.         if (!quietflag) {
  671.                 VOID fprintf(stderr,e, e1, e2, e3, e4, e5);
  672.                 nlflush(stderr);
  673.         }
  674. }
  675.  
  676.  
  677.  
  678. fflsbuf(c, iop)
  679. unsigned c; register FILE * iop;
  680. /* Function: Flush iop.
  681.  * Same routine as _flsbuf in stdio, but aborts program on error.
  682.  */
  683. {       register result;
  684.         if ((result=_flsbuf(c,iop))==EOF)
  685.                 writeerror();
  686.         return result;
  687. }
  688.  
  689.  
  690. fputs(s, iop)
  691. register char *s;
  692. register FILE *iop;
  693. /* Function: Put string s on file iop, abort on error.
  694.  * Same as puts in stdio, but with different putc macro.
  695.  */
  696. {
  697.     register r;
  698.     register c;
  699.  
  700.     while (c = *s++)
  701.         r = putc(c, iop);
  702.     return(r);
  703. }
  704.  
  705.  
  706.  
  707. fprintf(iop, fmt, va_alist)
  708. FILE *iop;
  709. char *fmt;
  710. va_dcl
  711. /* Function: formatted output. Same as fprintf in stdio,
  712.  * but aborts program on error
  713.  */
  714. {
  715.     register int value;
  716.     va_list ap;
  717.  
  718.     va_start(ap);
  719. #ifdef MSDOS
  720.     VOID vfprintf(iop, fmt, ap);
  721. #else
  722. #ifdef VFPRINTF
  723.     VOID vfprintf(iop, fmt, ap);
  724. #else
  725.     _doprnt(fmt, ap, iop);
  726. #endif
  727. #endif /* MSDOS */
  728.         if (ferror(iop)) {
  729.         writeerror();
  730.                 value = EOF;
  731.         } else value = 0;
  732.     va_end(ap);
  733.     return value;
  734. }
  735.  
  736.  
  737.  
  738. #ifdef LEXDB
  739. /* test program reading a stream of lexems and printing the tokens.
  740.  */
  741.  
  742.  
  743.  
  744. main(argc,argv)
  745. int argc; char * argv[];
  746. {
  747.         cmdid="lextest";
  748.         if (argc<2) {
  749.                 VOID fputs("No input file\n",stderr);
  750.                 exit(1);
  751.         }
  752.         if ((finptr=fopen(argv[1], "r")) == NULL) {
  753.                 faterror("Can't open input file %s\n",argv[1]);
  754.         }
  755.         Lexinit();
  756.         rewriteflag=false;
  757.         while (nexttok != EOFILE) {
  758.         switch (nexttok) {
  759.  
  760.         case ID:
  761.                 VOID printf("ID: %s",NextString);
  762.                 break;
  763.  
  764.         case NUM:
  765.                 if (hshenter==true)
  766.                    VOID printf("NUM: %s, index: %d",nexthsh->num, nexthsh-hshtab);
  767.                 else
  768.                    VOID printf("NUM, unentered: %s",NextString);
  769.                 hshenter = !hshenter; /*alternate between dates and numbers*/
  770.                 break;
  771.  
  772.         case COLON:
  773.                 VOID printf("COLON"); break;
  774.  
  775.         case SEMI:
  776.                 VOID printf("SEMI"); break;
  777.  
  778.         case STRING:
  779.                 readstring();
  780.                 VOID printf("STRING"); break;
  781.  
  782.         case UNKN:
  783.                 VOID printf("UNKN"); break;
  784.  
  785.         default:
  786.                 VOID printf("DEFAULT"); break;
  787.         }
  788.         VOID printf(" | ");
  789.         nextlex();
  790.         }
  791.         VOID printf("\nEnd of lexical analyzer test\n");
  792. }
  793.  
  794. cleanup()
  795. /* dummy */
  796. {}
  797.  
  798.  
  799. #endif
  800.